﻿using AbpDemo.Roles.Dto;
using AbpDemo.Roles;
using AbpDemo.Utility;
using Microsoft.AspNetCore.Mvc;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using Volo.Abp.Application.Dtos;
using Volo.Abp.Application.Services;
using Volo.Abp.Domain.Entities;
using Volo.Abp.Domain.Repositories;
using Volo.Abp.ObjectMapping;
using AbpDemo.Admins.Dto;
using System.Linq.Expressions;
using System.Linq.Dynamic.Core;

namespace AbpDemo
{
    public abstract class CrudAppExtService<TEntity, TEntityDto, TKey, TCreateUpdateDto> 
        : ApplicationService, ICrudAppExtService<TEntityDto, TKey, TCreateUpdateDto>
    where TEntity : class, IEntity<TKey>
    where TEntityDto : IEntityDto<TKey>
    {
        private readonly IRepository<TEntity, TKey> repository;

        public CrudAppExtService(IRepository<TEntity, TKey> repository)
        {
            this.repository = repository;
        }

        /// <summary>
        /// 添加
        /// </summary>
        /// <param name="createInput"></param>
        /// <returns></returns>
        public virtual async Task<ResultDto<TEntityDto>> CreateAsync(TCreateUpdateDto createInput)
        {
            var entity = ObjectMapper.Map<TCreateUpdateDto, TEntity>(createInput);
            await repository.InsertAsync(entity, autoSave: true);
            var dto = ObjectMapper.Map<TEntity, TEntityDto>(entity);
            return new ResultDto<TEntityDto> { Code = ResultState.Success, Data = dto, Message = ResultState.Success.EnumToDescription() };
        }

        /// <summary>
        /// 删除
        /// </summary>
        /// <param name="Id"></param>
        /// <returns></returns>
        public virtual async Task<ResultDto<bool>> DeleteAsync(TKey Id)
        {
            try
            {
                await repository.DeleteAsync(Id);
                return new ResultDto<bool> 
                {
                    Code = ResultState.Success,
                    Data = true,
                    Message = ResultState.Success.EnumToDescription()
                };
            }
            catch (Exception)
            {
                return new ResultDto<bool> 
                {
                    Code = ResultState.Success,
                    Data = false,
                    Message = ResultState.Success.EnumToDescription()
                };
            }
        }

        /// <summary>
        /// 按主键获取
        /// </summary>
        /// <param name="Id"></param>
        /// <returns></returns>
        public virtual async Task<ResultDto<TEntityDto>> GetAsync(TKey Id)
        {
            try
            {
                var entity = await repository.FindAsync(Id);
                var dto = ObjectMapper.Map<TEntity,TEntityDto>(entity);
                return new ResultDto<TEntityDto> 
                {
                    Code = ResultState.Success,
                    Data = dto
                };
            }
            catch (Exception)
            {
                throw;
            }
        }

        [NonAction]
        public virtual async Task<ResultDto<PagedResultDto<TEntityDto>>> BaseGetPageAsync([FromQuery]PageDto pageDto)
        {
            var query = await repository.GetPagedListAsync((pageDto.PageIndex - 1) * pageDto.PageSize,pageDto.PageSize,pageDto.Sorting);
            var pageData = ObjectMapper.Map<List<TEntity>, List<TEntityDto>>(query);
            var totalCount = await repository.CountAsync();
            return new ResultDto<PagedResultDto<TEntityDto>>
            {
                Code = ResultState.Success,
                Data = new PagedResultDto<TEntityDto>
                {
                    Items = pageData,
                    TotalCount = totalCount
                }
            };
        }

        [NonAction]
        public async Task<ResultDto<PagedResultDto<TEntityDto>>> BaseGetPageAsync(List<(bool, Expression<Func<TEntity, bool>>)> condition,PageDto dto)
        {
            var queryable = await repository.GetQueryableAsync();
            foreach (var item in condition)
            {
                queryable = queryable.WhereIf(item.Item1, item.Item2);
            }
            var page = ObjectMapper.Map<List<TEntity>, List<TEntityDto>>(queryable.OrderBy($"{nameof(AuditedEntityDto.CreationTime)} desc").Page(dto.PageIndex, dto.PageSize).ToList());
            var totalCount = queryable.Count();

            return new ResultDto<PagedResultDto<TEntityDto>>
            {
                Code = ResultState.Success,
                Data = new PagedResultDto<TEntityDto>
                {
                    Items = page,
                    TotalCount = totalCount
                }
            };
        }

        /// <summary>
        /// 更新
        /// </summary>
        /// <param name="Id"></param>
        /// <param name="createInput"></param>
        /// <returns></returns>
        public virtual async Task<ResultDto<TEntityDto>> UpdateAsync(TKey Id,TCreateUpdateDto createInput)
        {
            var entity = await repository.FindAsync(Id);
            ObjectMapper.Map(createInput, entity);
            await repository.UpdateAsync(entity,autoSave:true);
            var dto = ObjectMapper.Map<TEntity, TEntityDto>(entity);
            return new ResultDto<TEntityDto> 
            { 
                Code = ResultState.Success, 
                Data = dto, 
                Message = ResultState.Success.EnumToDescription() 
            };
        }
    }

}
